//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public License
// along with this program.  If not, see http://www.gnu.org/licenses/.
// 

#include "PolicyManager.h"

Define_Module(PolicyManager);

PolicyManager::PolicyManager() { }

PolicyManager::~PolicyManager() {
    /*{
        FILE *fDebug = fopen("distructordebug.txt", "a");
        if(fDebug != NULL) {
            char buff[64];
            int nChar = snprintf(buff, sizeof(buff), "PolicyManager. Destructor begin\r\n");
            fwrite(buff, 1, nChar, fDebug); fclose(fDebug);
        }
    }*/

    cancelAndDelete (msgStat);
    //cancelAndDelete (msgUpdate);

    delete (wifiQueue);
    delete (cellQueue);
    delete (energyFactor);

}

void PolicyManager::initialize(int stage) {
    if(stage == 0) {

        brainIn = findGate("controlIn");
        brainOut = findGate("controlOut");

        updateIntervalTime = par("updateInterval");

        wifiQueue = new cOutVector("Wifi Queue Factor");
        cellQueue = new cOutVector("Cellular Queue Factor");
        energyFactor = new cOutVector("Energy Factor");
        last_wifi_factor = -1;
        last_cell_factor = -1;
        last_energy_factor = -1;

        msgUpdate = new cMessage("updatePolicyManagerMsg");
        scheduleAt(simTime() + fabs(normal(updateIntervalTime, 0.1)), msgUpdate);

        msgStat = new cMessage("statPolicyManagerMsg");
        scheduleAt(simTime() + 0.5, msgStat);
    }
}

void PolicyManager::handleMessage(cMessage *msg) {
    if (msg->isSelfMessage()) {
        handleSelfMsg(msg);
    }
    else if (msg->getArrivalGateId() == brainIn) {
        handleBrainMsg(msg);
    }
    else {
        error("Unknown message received: %s", msg->getFullName());
        delete(msg);
    }
}

void PolicyManager::handleSelfMsg(cMessage *msg) {
    if(msg == msgUpdate) {
        updateMsg();

        scheduleAt(simTime() + fabs(normal(updateIntervalTime, 0.01)), msgUpdate);
    }
    else if(msg == msgStat) {

        if(last_wifi_factor >= 0) {
            wifiQueue->record(last_wifi_factor);
            cellQueue->record(last_cell_factor);
            energyFactor->record(last_energy_factor);
        }

        scheduleAt(simTime() + 0.5, msgStat);
    }
    else {
        error("Unknown self message received: %s", msg->getFullName());
        delete(msg);
    }
}


void PolicyManager::handleBrainMsg(cMessage *msg) {
    delete(msg);
}

void PolicyManager::finish() {
    cancelAndDelete(msgUpdate);
}

void PolicyManager::updateMsg(void) {

    PersonalStatusUpdate *newMsg = new PersonalStatusUpdate();
    double energy_factor, c_wifi_factor, c_cell_factor;

    //get node informations
    //getting mac queue information
    //Ieee80211Mac *mac = check_and_cast<Ieee80211Mac *>(this->getParentModule()->getParentModule()->getSubmodule("wlan", 0)->getSubmodule("mac"));
    //c_wifi_factor = mac->getQueueSize() / mac->getMaxQueueSize();
    Ieee80211MgmtBase *macMgmt = check_and_cast<Ieee80211MgmtBase *>(this->getParentModule()->getParentModule()->getSubmodule("wlan", 0)->getSubmodule("mgmt"));
    c_wifi_factor = macMgmt->getDataQueueSize() / macMgmt->getDataQueueCapacity();

    //getting 3g queue information
    Emulate3G *em3g = check_and_cast<Emulate3G *>(this->getParentModule()->getSubmodule("emulate3G"));
    c_cell_factor = em3g->getQueueSize() / em3g->getMaxQueueSize();

    //get energy information
    InetSimpleBattery *batt = check_and_cast<InetSimpleBattery *>(this->getParentModule()->getParentModule()->getSubmodule("battery"));
    energy_factor = batt->GetEnergy() / batt->GetInitialEnergy();

    newMsg->setEnergy_f(energy_factor);
    newMsg->setC_wifi_f(c_wifi_factor);
    newMsg->setC_cell_f(c_cell_factor);

    EV      << "Energy Factor: " << energy_factor
            << "C_WiFi Factor: " << c_wifi_factor
            << "C_Cell Factor: " << c_cell_factor
            << endl;

    //wifiQueue->record(c_wifi_factor);
    //cellQueue->record(c_cell_factor);
    //energyFactor->record(energy_factor);
    last_wifi_factor = c_wifi_factor;
    last_cell_factor = c_cell_factor;
    last_energy_factor = energy_factor;

    //update personal informations
    send(newMsg, brainOut);
}

